/*
 * Copyright 2022. Huawei Technologies Co., Ltd. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.jenkins.plugins.storage;

import com.cloudbees.plugins.credentials.BaseCredentials;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.model.TaskListener;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl;
import org.jenkinsci.plugins.workflow.steps.*;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * pipeline语法支持obs文件上传
 */
public class OBSUploadPipelineStep extends Step {
    private String ak;

    private String sk;

    private String credentialsId;

    private String bucket;

    private String endpoint;

    // 本地文件路径
    private String file;

    // 桶上文件路径
    private String path;

    // kms加密密钥id
    private String kmsId;

    // 包含文件正则路径
    private String includePathPattern;

    // 排除文件正则路径
    private String excludePathPattern;

    // 本地文件根目录
    private String workingDir;

    // 用户自定义标签，暂未使用
    private String[] metadatas;

    // 访问权限设置
    private String acl;

    // 指定对象被下载时的网页的缓存格式
    private String cacheControl;

    // 缓存过期时间
    private String expires;

    // 指定对象被下载时的内容编码格式
    private String contentEncoding;

    // 设置对象的文件类型
    private String contentType;

    // 提供一个默认的文件名赋值给该对象
    private String contentDisposition;

    // 重定向
    private String redirectLocation;

    public String getAk() {
        return ak;
    }

    @DataBoundSetter
    public void setAk(String ak) {
        this.ak = ak;
    }

    public String getSk() {
        return sk;
    }

    @DataBoundSetter
    public void setSk(String sk) {
        this.sk = sk;
    }

    public String getCredentialsId() {
        return credentialsId;
    }

    @DataBoundSetter
    public void setCredentialsId(String credentialsId) {
        this.credentialsId = credentialsId;
    }

    public String getBucket() {
        return bucket;
    }

    @DataBoundSetter
    public void setBucket(String bucket) {
        this.bucket = bucket;
    }

    public String getEndpoint() {
        return endpoint;
    }

    @DataBoundSetter
    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public String getFile() {
        return file;
    }

    @DataBoundSetter
    public void setFile(String file) {
        this.file = file;
    }

    public String getPath() {
        return path;
    }

    @DataBoundSetter
    public void setPath(String path){
        this.path = path;
    }

    public String getKmsId() {
        return kmsId;
    }

    @DataBoundSetter
    public void setKmsId(String kmsId) {
        this.kmsId = kmsId;
    }

    public String getIncludePathPattern() {
        return StringUtils.isBlank(includePathPattern) ? null : includePathPattern;
    }

    @DataBoundSetter
    public void setIncludePathPattern(String includePathPattern) {
        this.includePathPattern = includePathPattern;
    }

    public String getExcludePathPattern() {
        return StringUtils.isBlank(excludePathPattern) ? null : excludePathPattern;
    }

    @DataBoundSetter
    public void setExcludePathPattern(String excludePathPattern) {
        this.excludePathPattern = excludePathPattern;
    }

    public String getWorkingDir() {
        return workingDir;
    }

    @DataBoundSetter
    public void setWorkingDir(String workingDir) {
        this.workingDir = workingDir;
    }

    public String[] getMetadatas() {
        return metadatas;
    }

    @DataBoundSetter
    public void setMetadatas(String[] metadatas) {
        this.metadatas = metadatas;
    }

    public String getAcl() {
        return acl;
    }

    @DataBoundSetter
    public void setAcl(String acl) {
        this.acl = acl;
    }

    public String getCacheControl() {
        return cacheControl;
    }

    @DataBoundSetter
    public void setCacheControl(String cacheControl) {
        this.cacheControl = cacheControl;
    }

    public String getExpires() {
        return expires;
    }

    @DataBoundSetter
    public void setExpires(String expires) {
        this.expires = expires;
    }

    public String getContentEncoding() {
        return contentEncoding;
    }

    @DataBoundSetter
    public void setContentEncoding(String contentEncoding) {
        this.contentEncoding = contentEncoding;
    }

    public String getContentType() {
        return contentType;
    }

    @DataBoundSetter
    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public String getContentDisposition() {
        return contentDisposition;
    }

    @DataBoundSetter
    public void setContentDisposition(String contentDisposition) {
        this.contentDisposition = contentDisposition;
    }

    public String getRedirectLocation() {
        return redirectLocation;
    }


    public void setRedirectLocation(String redirectLocation) {
        this.redirectLocation = redirectLocation;
    }

    @DataBoundConstructor
    public OBSUploadPipelineStep(String bucket, String endpoint) {
        this.bucket = bucket;
        this.endpoint = endpoint;
    }

    @Override
    public StepExecution start(StepContext context) throws Exception {
        return new Execution(this, context);
    }

    @Extension
    public static class DescriptorImpl extends StepDescriptor {

        @Override
        public Set<? extends Class<?>> getRequiredContext() {
            return requires(TaskListener.class, EnvVars.class, FilePath.class);
        }

        @Override
        public String getFunctionName() {
            return "OBSPipelineUpload";
        }

        @Override
        public String getDisplayName() {
            return "华为云OBS上传";
        }
    }

    public static <T extends Class<?>> Set<T> requires(T... classes) {
        return new HashSet<>(Arrays.asList(classes));
    }

    public static class Execution extends SynchronousNonBlockingStepExecution<String> {

        protected static final long serialVersionUID = 1L;

        protected final transient OBSUploadPipelineStep step;

        public Execution(OBSUploadPipelineStep step, StepContext context) {
            super(context);
            this.step = step;

        }

        @Override
        public String run() throws Exception {
            StringCredentialsImpl credentials = ObsService.getLoginInformation(step.getCredentialsId());
            CustomInput  customInput = new CustomInput();
            if (!validCredentials(credentials, customInput)) {
                customInput.setAk(step.getAk());
                customInput.setSk(step.getSk());
            }
            customInput.setBucket(step.getBucket());
            customInput.setEndpoint(step.getEndpoint());
            customInput.setFile(step.getFile());
            customInput.setPath(step.getPath());
            customInput.setKmsId(step.getKmsId());
            customInput.setIncludePathPattern(step.getIncludePathPattern());
            customInput.setExcludePathPattern(step.getExcludePathPattern());
            customInput.setWorkingDir(step.getWorkingDir());
            customInput.setMetadatas(step.getMetadatas());
            customInput.setAcl(step.getAcl());
            customInput.setCacheControl(step.getCacheControl());
            customInput.setExpires(step.getExpires());
            customInput.setContentEncoding(step.getContentEncoding());
            customInput.setContentType(step.getContentType());
            customInput.setContentDisposition(step.getContentDisposition());
            customInput.setRedirectLocation(step.getRedirectLocation());
            TaskListener listener = Execution.this.getContext().get(TaskListener.class);
            return ObsService.upload(this.getContext().get(EnvVars.class), this.getContext().get(FilePath.class), listener, customInput);
        }

        private boolean validCredentials(StringCredentialsImpl credentials, CustomInput customInput) {
            if(credentials == null || credentials.getSecret() == null || StringUtils.isBlank(credentials.getSecret().getPlainText())) {
                return false;
            }
            String[] keys = credentials.getSecret().getPlainText().split(",");
            if (keys.length != 2) {
                return false;
            }
            customInput.setAk(keys[0].trim());
            customInput.setSk(keys[1].trim());
            return true;


        }
    }
}
